package com.ruoyi.znjc.scheduler;

import java.time.*;
import java.util.*;

import com.fasterxml.jackson.databind.JsonNode;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.system.domain.PestDisease2;
import com.ruoyi.znjc.domain.ZnjcRuleswarnlog;
import com.ruoyi.system.service.ICropCategoryService;
import com.ruoyi.system.service.IPestDiseaseService2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.ruoyi.znjc.domain.ZnjcTimers;
import com.ruoyi.znjc.service.IZnjcTimersService;
import com.ruoyi.znjc.service.IZnjcRuleswarnlogService;
import com.ruoyi.znjc.service.impl.ZnjcLLMService;
import com.ruoyi.common.utils.DateUtils;
import java.time.LocalDateTime;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.text.similarity.LevenshteinDistance;


import static com.ruoyi.common.core.text.Convert.toDouble;
import static com.ruoyi.common.core.text.Convert.toLong;

@Component
public class ZnjcTimerScheduler {

    @Autowired
    private ZnjcLLMService znjcLLMService;

    @Autowired
    private IPestDiseaseService2 pestDiseaseService;

    @Autowired
    private IZnjcTimersService znjcTimersService;

    @Autowired
    private IZnjcRuleswarnlogService ruleswarnlogService;

    @Autowired
    private ICropCategoryService cropCategoryService;


    @Autowired
    private IZnjcRuleswarnlogService znjcRuleswarnlogService;


    private List<Map<String, Object>> testPestDiseaseQuery() {
        PestDisease2 query = new PestDisease2();
        List<Map<String, Object>> resultList = znjcRuleswarnlogService.selectPestDiseaseWithCategoryName(query);
        return resultList;
    }

    // 模糊匹配，返回最匹配的病害Map

    public static class MatchResult {
        public Map<String, Object> diseaseMap;
        public int distance;
        public double similarity;  // 1 - 距离/最大长度，作为匹配概率（简单计算）

        public MatchResult(Map<String, Object> diseaseMap, int distance, double similarity) {
            this.diseaseMap = diseaseMap;
            this.distance = distance;
            this.similarity = similarity;
        }
    }
    private MatchResult findBestMatchDisease(String diseaseName, List<Map<String, Object>> diseases) {
        if (diseaseName == null || diseaseName.isEmpty() || diseases == null || diseases.isEmpty()) {
            return null;
        }

        LevenshteinDistance levenshtein = new LevenshteinDistance();
        Map<String, Object> bestMatch = null;
        int minDistance = Integer.MAX_VALUE;

        for (Map<String, Object> diseaseMap : diseases) {
            String name = (String) diseaseMap.get("name");
            String categoryName = (String) diseaseMap.get("categoryName");

            int distName = name == null ? Integer.MAX_VALUE : levenshtein.apply(diseaseName, name);
            int distCategory = categoryName == null ? Integer.MAX_VALUE : levenshtein.apply(diseaseName, categoryName);
            int dist = Math.min(distName, distCategory);

            if (dist < minDistance) {
                minDistance = dist;
                bestMatch = diseaseMap;
            }
        }

        // 阈值判断
        if (minDistance > 5) {
            return null;
        }

        // 计算匹配概率（简单版本）
        int maxLen = Math.max(diseaseName.length(),
                bestMatch.get("name") != null ? ((String)bestMatch.get("name")).length() : 1);
        double similarity = 1.0 - (double) minDistance / maxLen;

        return new MatchResult(bestMatch, minDistance, similarity);
    }


    /**
     * 模拟获取全部环境数据，返回时间-数据键值对列表
     */
    private List<Map.Entry<LocalDateTime, String>> getMockEnvDataEntries() {
        Map<LocalDateTime, String> timeDataMap = new LinkedHashMap<>();

        // 2025年8月6日 三条数据
        timeDataMap.put(LocalDateTime.of(2025, 8, 6, 7, 30),
                "2025-08-06 07:30 温度: 22°C, 湿度: 60%, 光照: 200lx, 风速: 3.2m/s, 降雨量: 0mm, 土壤水分: 18%");
        timeDataMap.put(LocalDateTime.of(2025, 8, 6, 12, 0),
                "2025-08-06 12:00 温度: 28°C, 湿度: 70%, 光照: 400lx, 风速: 4.5m/s, 降雨量: 0mm, 土壤水分: 24%");
        timeDataMap.put(LocalDateTime.of(2025, 8, 6, 18, 0),
                "2025-08-06 18:00 温度: 26°C, 湿度: 65%, 光照: 350lx, 风速: 3.8m/s, 降雨量: 0mm, 土壤水分: 22%");

        // 2025年7月10日 三条数据
        timeDataMap.put(LocalDateTime.of(2025, 7, 10, 8, 0),
                "2025-07-10 08:00 温度: 25°C, 湿度: 55%, 光照: 300lx, 风速: 3.1m/s, 降雨量: 0mm, 土壤水分: 22%");
        timeDataMap.put(LocalDateTime.of(2025, 7, 10, 12, 0),
                "2025-07-10 12:00 温度: 30°C, 湿度: 50%, 光照: 450lx, 风速: 4.0m/s, 降雨量: 0mm, 土壤水分: 20%");
        timeDataMap.put(LocalDateTime.of(2025, 7, 10, 18, 0),
                "2025-07-10 18:00 温度: 28°C, 湿度: 52%, 光照: 350lx, 风速: 3.5m/s, 降雨量: 0mm, 土壤水分: 21%");

        return new ArrayList<>(timeDataMap.entrySet());
    }





    /**
     * 执行定时器对应的任务，并更新最后执行时间
     */
    // 每30分钟轮询执行一次定时任务，包含任务执行逻辑
    @Scheduled(cron = "0 0/30 * * * ?")
    public void executeTimers() {
        System.out.println("=======================【定时任务轮询开始】=======================");
        List<ZnjcTimers> timers = znjcTimersService.selectZnjcTimersList(new ZnjcTimers());
        System.out.println("📋 总定时器数量：" + timers.size());

        Date nowDate = DateUtils.getNowDate();
        long nowMillis = nowDate.getTime();
        LocalDate today = LocalDate.now();
        LocalDateTime now = LocalDateTime.now();

        for (ZnjcTimers timer : timers) {
            System.out.println("\n---------------【定时器 ID=" + timer.getTimerId() + "，名称=" + timer.getTimerName() + "】---------------");
            try {
                // 1. 检查定时器状态
                System.out.println(" 1. 检查定时器状态");
                if (!"active".equalsIgnoreCase(timer.getTimerStatus())) {
                    System.out.println("⛔ 定时器状态为非激活（当前状态：" + timer.getTimerStatus() + "），跳过执行");
                    continue;
                }
                System.out.println("✅ 定时器状态为激活");

                // 2. 检查定时器有效期
                System.out.println(" 2. 检查定时器有效期");
                Date startDate = timer.getEffectiveStartTime();
                Date endDate = timer.getEffectiveEndTime();
                if (startDate == null || endDate == null) {
                    System.out.println("⛔ 有效期起止时间为空，跳过执行");
                    continue;
                }
                LocalDate startLocalDate = DateUtils.dateToLocalDate(startDate);
                LocalDate endLocalDate = DateUtils.dateToLocalDate(endDate);
                System.out.printf("定时器有效期范围：%s ~ %s，当前日期：%s\n", startLocalDate, endLocalDate, today);
                if (today.isBefore(startLocalDate) || today.isAfter(endLocalDate)) {
                    System.out.println("⛔ 当前日期不在有效期范围内，跳过执行");
                    continue;
                }
                System.out.println("✅ 当前日期在有效期范围内");

                // 3. 判断轮询类型和执行间隔
                String pollType = timer.getPollType();
                System.out.println(" 3. 轮询类型：" + pollType);
                Date lastExec = timer.getLastExecuteTime();
                long lastExecMillis = (lastExec == null) ? 0 : lastExec.getTime();

                boolean shouldExecute = false;

                if ("interval".equalsIgnoreCase(pollType)) {
                    Long intervalHours = timer.getPollInterval();
                    if (intervalHours == null || intervalHours <= 0) {
                        System.out.println("⛔ 时间间隔无效，跳过执行");
                        continue;
                    }
                    long intervalMillis = intervalHours * 3600 * 1000;
                    System.out.printf("间隔类型，间隔时长：%d小时，上次执行时间：%s\n", intervalHours, lastExec);
                    if (lastExec == null || (nowMillis - lastExecMillis) >= intervalMillis) {
                        shouldExecute = true;
                    } else {
                        System.out.printf("⏳ 距离上次执行 %d 秒，未达到间隔时长，跳过\n", (nowMillis - lastExecMillis) / 1000);
                    }
                } else if ("fixedtime".equalsIgnoreCase(pollType)) {
                    LocalTime pollStart = timer.getPollStartTime();
                    LocalTime pollEnd = timer.getPollEndTime();
                    LocalTime nowTime = now.toLocalTime();
                    System.out.printf("固定时间类型，执行时间段：%s ~ %s，当前时间：%s\n", pollStart, pollEnd, nowTime);

                    if (pollStart != null && pollEnd != null &&
                            !nowTime.isBefore(pollStart) && !nowTime.isAfter(pollEnd)) {

                        long minIntervalMillis = 5 * 60 * 60 * 1000; // 5小时最小间隔
                        System.out.printf("上次执行时间：%s\n", lastExec);
                        if (lastExec == null || (nowMillis - lastExecMillis) >= minIntervalMillis) {
                            shouldExecute = true;
                        } else {
                            System.out.printf("⏳ 距离上次执行 %d 秒，未达到最小间隔，跳过\n", (nowMillis - lastExecMillis) / 1000);
                        }
                    } else {
                        System.out.println("⛔ 当前时间不在允许执行时间段内，跳过");
                    }
                } else {
                    System.out.println("⛔ 未知轮询类型：" + pollType + "，跳过执行");
                }

                if (!shouldExecute) {
                    continue;
                }

                // ========== 下面开始执行具体任务 ==========

                // 4. 获取并过滤模拟环境数据
                System.out.println(" 4. 获取并过滤模拟环境数据");
                List<Map.Entry<LocalDateTime, String>> allEnvDataEntries = getMockEnvDataEntries();
                LocalTime pollStartTime = timer.getPollStartTime();
                LocalTime pollEndTime = timer.getPollEndTime();

                LocalDateTime pollStartDateTime = (pollStartTime != null) ? LocalDateTime.of(today, pollStartTime) : null;
                LocalDateTime pollEndDateTime = (pollEndTime != null) ? LocalDateTime.of(today, pollEndTime) : null;

                System.out.printf("定时器轮询时间段：%s ~ %s\n", pollStartDateTime, pollEndDateTime);

                List<String> envData = new ArrayList<>();
                for (Map.Entry<LocalDateTime, String> entry : allEnvDataEntries) {
                    LocalDateTime dateTime = entry.getKey();
                    boolean inRange = (pollStartDateTime == null || pollEndDateTime == null)
                            || (!dateTime.isBefore(pollStartDateTime) && !dateTime.isAfter(pollEndDateTime));
                    if (inRange) {
                        envData.add(entry.getValue());
                    }
                }
                System.out.println("获取到的环境数据条数：" + envData.size());
                if (envData.isEmpty()) {
                    System.out.println("⚠️ 时间段内无匹配环境数据，使用默认提示继续执行");
                    envData = Collections.singletonList("未检测到对应时间内环境数据");
                }


                // 5. 查询规则内容并构造模型输入
                System.out.println(" 5. 查询规则内容并构造模型输入");
                Map<String, Object> ruleInfo = znjcTimersService.selectRuleInfoByTimerId(timer.getTimerId());
                Map<String, Object> innerMap = (ruleInfo != null && !ruleInfo.isEmpty())
                        ? (Map<String, Object>) ruleInfo.values().iterator().next()
                        : null;

                String ruleContent = (innerMap != null) ? (String) innerMap.get("rule_content") : null;
                String ruleId = (innerMap != null) ? String.valueOf(innerMap.get("rule_id")) : null;
                System.out.println("查询到的规则内容：" + (ruleContent != null ? ruleContent : "无"));

                Map<String, Object> requestMap = new HashMap<>();
                requestMap.put("ruleContent", ruleContent);
                requestMap.put("environmentData", envData);

                // 6. 发送给大模型并解析响应
                System.out.println(" 6. 发送给大模型并解析响应");
                String llmResponse;
                try {
                    llmResponse = znjcLLMService.chatWithTimerData(requestMap);
                } catch (Exception e) {
                    System.out.println("模型调用失败：" + e.getMessage());
                    continue; // 跳过当前定时器，执行下一个
                }
                JsonNode contentNode = new ObjectMapper()
                        .readTree(llmResponse)
                        .path("choices").get(0)
                        .path("message").path("content");

                String contentText = contentNode.asText().trim()
                        .replaceAll("(?i)```json", "")
                        .replaceAll("```", "")
                        .trim();
                JsonNode dataNode = new ObjectMapper().readTree(contentText);

                String disease = dataNode.path("disease").asText(null);
                double probability = dataNode.path("probability").asDouble(0);

                Map<String, Object> llmResult = new HashMap<>();
                llmResult.put("disease", disease);
                llmResult.put("probability", probability);
                System.out.println("📊 大模型解析结果: " + llmResult);

                if (probability >= 0.5 && disease != null && !disease.isEmpty()) {
                    System.out.printf("⚠️ 检测到病害: %s，概率: %.2f\n", disease, probability);
                    // TODO: 触发预警业务
                } else {
                    System.out.println("✅ 病害概率低于阈值（< 0.5），不生成预警");
                }

                // 7. 匹配防治信息
                System.out.println("-----------------------大模型匹配防治建议-----------------------");
                List<Map<String, Object>> diseaseList = testPestDiseaseQuery();
                MatchResult matchResult = findBestMatchDisease(disease, diseaseList);

                String prevention = null;
                if (matchResult != null) {
                    Long diseaseId = Long.parseLong(matchResult.diseaseMap.get("id").toString());
                    PestDisease2 diseaseDetail = pestDiseaseService.selectPestDiseaseById(diseaseId);
                    System.out.printf("匹配到的病害名称: %s，唯一ID: %s，匹配距离: %d，匹配概率: %.2f%%\n",
                            disease, diseaseId, matchResult.distance, matchResult.similarity * 100);
                    if (diseaseDetail != null) {
                        prevention = diseaseDetail.getControlMethods();
                        System.out.println("防治信息：" + prevention);
                    } else {
                        System.out.println("未找到病害详细信息");
                    }
                } else {
                    System.out.println("未匹配到对应的病害ID");
                }
                System.out.println("--------------------------------------------------------------");

                // 8. 构造日志数据并写入日志表
                System.out.println("-----------------------规则预警日志构造数据-----------------------");
                Map<String, Object> logMap = new LinkedHashMap<>();
                logMap.put("timerId", timer.getTimerId());
                logMap.put("subId", timer.getUsersubId());
                try {
                    logMap.put("ruleId", Integer.parseInt(ruleId));
                } catch (Exception e) {
                    logMap.put("ruleId", null);
                }
                logMap.put("ruleSnapshot", ruleContent);
                logMap.put("envSnapshot", new ObjectMapper().writeValueAsString(envData));
                logMap.put("probability", probability);
                logMap.put("isTriggered", probability > 0.5 ? "true" : "false");
                logMap.put("modelId", null);
                logMap.put("modelSuggestion", prevention);
                logMap.put("createTime", nowDate);

                for (Map.Entry<String, Object> entry : logMap.entrySet()) {
                    System.out.println(entry.getKey() + ": " + entry.getValue());
                }
                System.out.println("--------------------------------------------------------------");

                ZnjcRuleswarnlog log = new ZnjcRuleswarnlog();
                log.setTimerId(Convert.toLong(logMap.get("timerId")));
                log.setSubId(Convert.toLong(logMap.get("subId")));
                log.setRuleId(Convert.toLong(logMap.get("ruleId")));
                log.setRuleSnapshot((String) logMap.get("ruleSnapshot"));
                log.setEnvSnapshot((String) logMap.get("envSnapshot"));
                log.setIsTriggered((String) logMap.get("isTriggered"));
                log.setModelId(Convert.toLong(logMap.get("modelId")));
                log.setModelSuggestion((String) logMap.get("modelSuggestion"));

                Double probDouble = (Double) logMap.get("probability");
                log.setProbability(probDouble != null ? Math.round(probDouble) : null);

                znjcRuleswarnlogService.insertZnjcRuleswarnlog(log);
                System.out.println("✅ 规则预警日志已写入数据库");

                // 9. 更新定时器最后执行时间
                timer.setLastExecuteTime(nowDate);
                znjcTimersService.updateZnjcTimers(timer);
                System.out.println("✅ 定时器最后执行时间已更新");

            } catch (Exception e) {
                System.out.println("❌ [任务异常] 定时器ID=" + timer.getTimerId() + " 执行失败");
                e.printStackTrace();
            }
        }
        System.out.println("");
        System.out.println("=======================【定时任务轮询结束】=======================\n");
    }


}



